home *** CD-ROM | disk | FTP | other *** search
/ Alles Voor Internet / Tout Pour Internet / alles voor internet.iso / MacInternet™ / Telnet / NCSA / tn3270 2.4d7 source / NCSA⁄BYU TCP⁄IP / tools.c < prev    next >
Text File  |  1991-06-27  |  15KB  |  593 lines

  1. /*
  2. *      TOOLS.C
  3. *
  4. ****************************************************************************
  5. *                                                                          *
  6. *      part of:                                                            *
  7. *      TCP/IP kernel for NCSA Telnet                                       *
  8. *      by Tim Krauskopf                                                    *
  9. *                                                                          *
  10. *      National Center for Supercomputing Applications                     *
  11. *      152 Computing Applications Building                                 *
  12. *      605 E. Springfield Ave.                                             *
  13. *      Champaign, IL  61820                                                *
  14. *                                                                          *
  15. *    Copyright (c) 1987, Board of Trustees of the University of Illinois   *
  16. *                                                                          *
  17. ****************************************************************************
  18. *
  19. *  Portions of the driver code that are not specific to a particular protocol
  20. *
  21. */
  22. #include <stdio.h>
  23. #include "protocol.h"
  24. #include "data.h"
  25. #include "mactools.h"
  26. #include "tcp.h"
  27.  
  28. #include <Events.h>
  29. #include <String.h>
  30.  
  31.  
  32. /***************************************************************************/
  33. /*  enqueue
  34. *   add something to a TCP queue.  Used by both 'write()' and tcpinterpret
  35. *   WINDOWSIZE is the size limitation of the advertised window.
  36. */
  37. int enqueue
  38.   (
  39.     struct window *wind,
  40.     char *buffer,
  41.     int nbytes
  42.   )
  43.     {
  44.     int i;
  45.     
  46.     i = WINDOWSIZE - wind->contain;
  47.     if (i <= 0 || nbytes == 0)
  48.         return(0);                        /* no room at the inn */
  49.  
  50.     if (nbytes > i)
  51.         nbytes = i;
  52.  
  53.     i = wind->where - wind->endlim;        /* room at end */
  54.     i += WINDOWSIZE;
  55.  
  56.     if (i < nbytes) {
  57.         movebytes(wind->endlim,buffer,i);
  58.         movebytes(wind->where,(char *)(buffer+i),nbytes-i);
  59.         wind->endlim = wind->where + nbytes - i;
  60.     } 
  61.     else {
  62.         movebytes(wind->endlim,buffer,nbytes);        /* fits in one chunk */
  63.         wind->endlim += nbytes;
  64.     }
  65.     wind->contain += nbytes;            /* more stuff here */
  66.  
  67.     return(nbytes);
  68.  
  69. }
  70.  
  71. /*************************************************************************/
  72. /* dequeue
  73. *     used by read, this copies data out of the queue and then
  74. *  deallocates it from the queue.
  75. *  cpqueue and rmqueue are very similar and are to be used by tcpsend
  76. *  to store unacknowledged data.
  77. *
  78. *  returns number of bytes copied from the queue
  79. */
  80. int dequeue
  81.   (
  82.     struct window *wind,
  83.     char *buffer,
  84.     int nbytes                /* maximum number to copy out */
  85.   )
  86.     {
  87.     int i;
  88.  
  89.     if (wind->contain == 0)
  90.         return(0);
  91.  
  92.     if (wind->contain < nbytes)
  93.         nbytes = wind->contain;
  94.  
  95.     i = wind->endbuf - wind->base;
  96.  
  97.     if (i <= nbytes) {
  98.         movebytes(buffer,wind->base,i);
  99.         movebytes((char *)(buffer+i),wind->where,nbytes-i);
  100.         wind->base = wind->where + nbytes-i;
  101.     }
  102.     else {
  103.         movebytes( buffer, wind->base, nbytes);
  104.         if (wind->contain == nbytes) 
  105.             wind->base = wind->endlim = wind->where;
  106.         else
  107.             wind->base += nbytes;
  108.     }
  109.     
  110.     wind->contain -= nbytes;
  111.  
  112.     return(nbytes);
  113.  
  114. }
  115.  
  116. #ifdef notneeded
  117. /**************************************************************************/
  118. /*  cpqueue
  119. *       does the same thing as dequeue, but does not deallocate the data
  120. *   used when transmitting TCP data.  When the data is ACKed, then 
  121. *   rmqueue is called to deallocate the correct amount of data.
  122. */
  123. cpqueue(wind,buffer,nbytes)
  124.     struct window *wind;
  125.     char *buffer;
  126.     int nbytes;                /* maximum number to copy out */
  127.     {
  128.     int i;
  129.  
  130.     if (wind->contain == 0)
  131.         return(0);
  132.  
  133.     if (wind->contain < nbytes)
  134.         nbytes = wind->contain;
  135.  
  136.     i = wind->endbuf - wind->base;
  137.  
  138.     if (i < nbytes) {
  139.         movebytes(buffer,wind->base,i);
  140.         movebytes((char *)(buffer+i),wind->where,nbytes-i);
  141.     }
  142.     else 
  143.         movebytes( buffer, wind->base, nbytes);
  144.     
  145.     return(nbytes);
  146.  
  147. }
  148. #endif
  149.  
  150. /**************************************************************************/
  151. /*  rmqueue
  152. *     does the queue deallocation that is left out of cpqueue
  153. *
  154. *   rmqueue of WINDOWSIZE or greater bytes will empty the queue
  155. */
  156. int rmqueue
  157.   (
  158.     struct window *wind,
  159.     int nbytes                    /* number to remove */
  160.   )
  161.     {
  162.     int i;
  163.  
  164.     if (wind->contain < nbytes)
  165.         nbytes = wind->contain;
  166.  
  167.     i = wind->endbuf - wind->base;
  168.  
  169.     if (i <= nbytes) 
  170.         wind->base = wind->where+nbytes-i;
  171.     else {
  172.         if (wind->contain == nbytes)
  173.             wind->base = wind->endlim = wind->where;
  174.         else
  175.             wind->base += nbytes;
  176.     }
  177.     
  178.     wind->contain -= nbytes;
  179.  
  180.     return(nbytes);
  181.  
  182. }
  183.  
  184.  
  185. /************************************************************************/
  186. /* comparen
  187. *  Take n bytes and return identical (true=1) or not identical (false=0)
  188. *
  189. *  Could be written in assembler for improved performance
  190. */
  191. int comparen
  192.   (
  193.     uint8 *s1,
  194.     uint8 *s2,
  195.     register int n
  196.   )
  197.     {
  198.  
  199.     while (n--)
  200.         if (*s1++ != *s2++)
  201.             return(0);
  202.  
  203.     return(1);
  204.  
  205. }
  206.  
  207. /***********************************************************************/
  208. /*  netgetevent
  209. *   Retrieves the next event (and clears it) which matches bits in
  210. *   the given mask.  Returns the event number or -1 on no event present.
  211. *   Also returns the exact class and the associated integer in reference
  212. *   parameters.
  213. *
  214. *   The way the queue works:
  215. *     There is always a dummy record pointed to by nnelast.
  216. *     When data is put into the queue, it goes into nnelast, then nnelast
  217. *        looks around for another empty one to obtain.
  218. *        It looks at nnefree first, then bumps one from nnefirst if necessary.
  219. *     When data is retrieved, it is searched from nnefirst to nnelast.
  220. *        Any freed record is appended to nnefree.
  221. */
  222. int netgetevent
  223.   (
  224.     uint8 mask,
  225.     int *retclass,
  226.     int *retint
  227.   )
  228.     {
  229.     int i,j;
  230.  
  231.     i = j = nnefirst;
  232.  
  233.     while (i != nnelast) {
  234.         if (mask & nnq[i].eclass) {
  235.             if (i == nnefirst) 
  236.                 nnefirst = nnq[nnefirst].next;        /* step nnefirst */
  237.             else 
  238.                 nnq[j].next = nnq[i].next;            /* bypass record i */
  239.  
  240.             nnq[i].next = nnefree;
  241.             nnefree = i;                            /* install in free list */
  242.             *retint = nnq[i].idata;
  243.             *retclass = nnq[i].eclass;
  244.             return(nnq[i].event);
  245.         }
  246.         j = i;
  247.         i = nnq[i].next;
  248.     }
  249.  
  250.     return(0);
  251.  
  252. }
  253.  
  254. /***********************************************************************/
  255. /*  netputevent
  256. *   add an event to the queue.
  257. *   Will probably get the memory for the entry from the free list.
  258. *   Returns 0 if there was room, 1 if an event was lost.
  259. */
  260. int netputevent
  261.   (
  262.     int class,
  263.     int what,
  264.     int dat
  265.   )
  266.     {
  267.     int i; 
  268.     
  269.     i = nnelast;
  270.     nnq[i].eclass = class;                    /* put data in */
  271.     nnq[i].event = what;
  272.     nnq[i].idata = dat;
  273.  
  274.     if (nnefree >= 0) {                        /* there is a spot in free list */
  275.         nnq[i].next = nnelast = nnefree;
  276.         nnefree = nnq[nnefree].next;        /* remove from free list */
  277.         return(0);
  278.     }
  279.     else {
  280.         nnq[i].next = nnelast = nnefirst;
  281.         nnefirst = nnq[nnefirst].next;        /* lose oldest event */
  282.         return(1);
  283.     }
  284. }
  285.  
  286. /***************************************************************************/
  287. /*  netputuev
  288. *   put a unique event into the queue
  289. *   First searches the queue for like events
  290. */
  291. int netputuev
  292.   (
  293.     int class,
  294.     int what,
  295.     int dat
  296.   )
  297.     {
  298.     int i;
  299.  
  300.     i = nnefirst;
  301.     while (i != nnelast) {
  302.         if (nnq[i].idata == dat && nnq[i].event == what &&
  303.             nnq[i].eclass == class)
  304.             return(0);
  305.         i = nnq[i].next;
  306.     }
  307.  
  308.     return(netputevent(class,what,dat));
  309.  
  310. }
  311.  
  312. /************************************************************************/
  313. /*  netposterr
  314. *   place an error into the event q
  315. *   Takes the error number and puts it into the error structure
  316. */
  317. void netposterr
  318.   (
  319.     int num
  320.   )
  321.   {
  322.  
  323.     if (netputevent(ERRCLASS,ERR1,num))
  324.  
  325.         netputuev(ERRCLASS,ERR1,501);            /* only if we lost an event */
  326.   }
  327.  
  328. /************************************************************************/
  329. /*  transq
  330. *
  331. *   Needed for TCP, not as general as cpqueue, 
  332. *   but is required for efficient uploading
  333. *
  334. *   Transmit the entire queue (window) to the other host without expecting
  335. *   any sort of acknowledgement.
  336. *
  337. */
  338. int transq
  339.   (
  340.     struct port *prt
  341.   )
  342.     {
  343.     uint bites;
  344.     int i,j,n;
  345.     struct window *wind;
  346.     uint32 saveseq;
  347.     uint8 *endb,*whereb,*baseb;
  348.  
  349.     if (prt == NULL) {
  350.         nnerror(406);        /* NULL port for trans */
  351.         return(-1);
  352.     }
  353.  
  354.     wind = &prt->out;
  355. /*
  356. *   find out how many bytes the other side will allow us to send (window)
  357. */
  358.     bites = wind->size;
  359.     if (wind->contain < bites)
  360.         bites = wind->contain;
  361.  
  362. /*
  363. *  set up the tcp packet for this, ACK field is same for all packets
  364. */
  365.     prt->tcpout.t.ack = longswap(prt->in.nxt);
  366. /*
  367. *  any more flags should be set?
  368. */
  369.     if (wind->push) {                    /* is push indicator on? */
  370.         prt->tcpout.t.flags |= TPUSH;
  371.         wind->push = 0;
  372.     }
  373.  
  374.     if ((bites <= 0) || prt->state != SEST) {    /* if no data to send . . . */
  375.         tcpsend(prt,0);                /* just a retransmission or ACK */
  376.         return(0);
  377.     }
  378.  
  379. /*
  380. *  we have data to send, get the correct sequence #'s 
  381. */
  382.     saveseq = wind->nxt;
  383.  
  384.     whereb = wind->where;
  385.     endb = wind->endbuf;
  386.     baseb = wind->base;
  387. /*
  388. *  in a loop, transmit the entire queue of data 
  389. */
  390.     for (i=0 ; i < bites; i += prt->sendsize) {
  391.         n = prt->sendsize;
  392.         if (i + n > bites)
  393.             n = bites - i;
  394.  
  395.         j = endb - baseb;
  396.  
  397.         if (j < n) {
  398.             movebytes(prt->tcpout.x.data,baseb,j);
  399.             movebytes((char *)(prt->tcpout.x.data+j),whereb,n-j);
  400.             baseb = whereb + n-j;
  401.         }
  402.         else {
  403.             movebytes( prt->tcpout.x.data, baseb, n);
  404.             baseb += n;
  405.         }
  406.  
  407.         tcpsend(prt,n);                        /* send it */
  408.         wind->nxt += n;
  409.     }
  410.  
  411.     wind->nxt = saveseq;                    /* get back first seq # */
  412.  
  413.     return(0);
  414. } /* transq */
  415.  
  416. /************************************************************************/
  417. /*  netsleep
  418. *      sleep, while demuxing packets, so we don't miss anything
  419. *
  420. */
  421. int netsleep
  422.   (
  423.     int n
  424.   )
  425.     {
  426.     int i,nmux,redir;
  427.     int32 t,gt,start;
  428.     struct port *p;
  429.     uint8 *pc;
  430.  
  431.     redir = 0;
  432.     start = time(NULL);
  433.  
  434.     if (n)
  435.         t = start + n*TICKSPERSEC;
  436.     else
  437.         t = start;
  438.  
  439.     do {
  440.         nmux = demux(1);                /* demux all packets */
  441.  
  442. /*
  443. *  if there were packets in the incoming packet buffer, then more might
  444. *  have arrived while we were processing them.  This gives absolute priority
  445. *  to packets coming in from the network.
  446. */
  447.         if (nmux)
  448.             continue;
  449.  
  450.         if (IREDIR == netgetevent(ICMPCLASS,&i,&i))
  451.             redir = 1;
  452. /*
  453. *  Check each port to see if action is necessary.
  454. *  This now sends all Ack packets, due to p->lasttime being set to 0L.
  455. *  Waiting for nmux == 0 for sending ACKs makes sure that the network
  456. *  has a much higher priority and reduces the number of unnecessary ACKs.
  457. */
  458.         gt = time(NULL);
  459.  
  460.         for (i=0; i < NPORTS; i++) {
  461.             p = portlist[i];
  462.             if ((p != NULL) && (p->state > SLISTEN)) {
  463.  
  464.                 if (!p->out.lasttime) 
  465.                     transq(p);                /* takes care of all ACKs */
  466.  
  467.                 else if ((p->out.contain > 0) || (p->state > SEST)) {
  468. /*
  469. *  if a retransmission timeout occurs, exponential back-off.
  470. *  This number returns toward the correct value by the RTT measurement
  471. *  code in ackcheck.
  472. *
  473. *  fix: 5/12/88, if timer was at MAXRTO, transq didn't get hit - TK
  474. */
  475.                     if ((p->out.lasttime + p->rto < gt)) {
  476.                         if (p->rto < MAXRTO) 
  477.                             p->rto <<= 1;        /* double it */
  478.                         transq(p);
  479.                     }
  480.                 }
  481.  
  482.                 if ((p->out.lasttime + POKEINTERVAL < gt) && 
  483.                     (p->state == SEST))
  484.                     transq(p);
  485. /*
  486. *  check to see if ICMP redirection occurred and needs servicing.
  487. *  If it needs servicing, try to get the new hardware address for the new 
  488. *  gateway.  If an arp was sent during getdlayer, we assume another ICMP
  489. *  redirect will occur, this routine will reactivate, and then the hardware
  490. *  address will be available in the cache.
  491. */
  492.                 if (redir && comparen(p->tcpout.i.ipdest,nnicmpsave,4)) {
  493.                     pc = getdlayer(nnicmpnew);
  494.                     if (pc != NULL)
  495.                         movebytes(p->tcpout.d.dest,pc,DADDLEN);
  496.                 }
  497.             }
  498.         }
  499.         redir = 0;                /* reset flag for next demux */
  500.  
  501.     } while ((t > time(NULL))         /* done yet? */
  502.         && (time(NULL) >= start));  /* allow for wraparound of timer */
  503.  
  504.  
  505.     return(nmux);                /* will demux once, even for sleep(0) */
  506.  
  507. } /* netsleep */
  508.  
  509. /************************************************************************/
  510. /*  neterrstring
  511. *   returns the string associated with a particular error number
  512. *
  513. *   error number is formatted %4d at the beginning of the string
  514. */
  515. static char *errs[] = {"   0 Error unknown",
  516.             " 100 Network jammed, probable break in wire",
  517.             " 101 Could not initialize hardware level network driver",
  518.             " 102 ERROR: The conflicting machine is using the same IP number",
  519.             " 103 RARP request failed, an IP number is required",
  520.             " 300 Bad IP checksum",
  521.             " 301 IP packet not for me",
  522.             " 302 IP packet with options received",
  523.             " 303 IP: unknown higher layer protocol",
  524.             " 304 IP: fragmented packet received, frags not supported",
  525.             " 400 TCP: bad checksum",
  526.             " 401 ACK invalid for TCP syn sent",
  527.             " 403 TCP in unknown state",
  528.             " 404 Invalid port for TCPsend",
  529.             " 405 TCP connection reset by other host",
  530.             " 406 Null port specified for ackandtrans",
  531.             " 407 Packet received for invalid port -- reset sent",
  532.             " 500 No internal TCP ports available",
  533.             " 501 Warning: Event queue filled, probably non-fatal",
  534.             " 504 Local host or gateway not responding",
  535.             " 505 Memory allocation error, cannot open port",
  536.             " 506 Not allowed to connect to broadcast address",
  537.             " 507 Reset received: syn sent, host is refusing connection",
  538.             " 600 ICMP:    Echo reply",
  539.             " 603 ICMP:    Destination unreachable",
  540.             " 604 ICMP:    Source Quench",
  541.             " 605 ICMP:    Redirect, another gateway is more efficient",
  542.             " 608 ICMP:    Echo requested (ping requested)",
  543.             " 611 ICMP:    Time Exceeded on Packet",
  544.             " 612 ICMP:    Parameter problem in IP",
  545.             " 613 ICMP:    Timestamp request",
  546.             " 614 ICMP:    Timestamp reply",
  547.             " 615 ICMP:    Information request",
  548.             " 616 ICMP:    Information reply",
  549.             " 699 ICMP: Checksum error",
  550.             " 700 Bad UDP checksum",
  551.             " 800 Domain: Name request to server failed",
  552.             " 801 Domain: Using default domain",
  553.             " 802 Domain: name does not exist",
  554.             " 803 Domain: UDP name server did not resolve the name",
  555.             " 804 Domain: name server failed, unknown reason",
  556.             " 805 Host machine not in configuration file",
  557.             " 806 Missing IP number, requires domain lookup",
  558.             " 900 Session: Cannot find or open configuration file",
  559.             " 901 Session: Cannot allocate memory for processing",
  560.             " 902 Session: Invalid keyword in configuration file",
  561.             " 903 Session: Element too long (>200), maybe missing quote",
  562.             " 904 Session: Probable missing quote marks, a field must be on one line",
  563.             " 905 Session: 'name' field required before other machine entries",
  564.             " 906 Session: Syntax error, invalid IP number",
  565.             " 907 Session: Syntax error, Subnet mask invalid",
  566.             " 908 Session: Syntax error, IP address for this PC is invalid",
  567.  
  568.                         ""};
  569.  
  570. static char errspace[80];        /* room for user-defined errors */
  571.  
  572. char *neterrstring(errno)
  573.     int errno;
  574.     {
  575.     int i;
  576.     char s[10];
  577.  
  578.     if (errno < 0) 
  579.         return(errspace);
  580.  
  581.     sprintf(s,"%4d",errno);
  582.     i = 0;
  583.     do {
  584.         if (!strncmp(errs[i],s,4))
  585.             return(errs[i]+5);            /* pointer to error message  */
  586.         i++;
  587.  
  588.     } while (*errs[i] || i > 100);            /* until NULL found */
  589.  
  590.     return(errs[0]+5);                    /* error unknown */
  591. }
  592.  
  593.